package ca.mcgill.model.implementation.factory;

import java.util.ArrayList;
import java.util.List;

import ca.mcgill.model.functional.Action;
import ca.mcgill.model.functional.AsynchronousFSMsNetwork;
import ca.mcgill.model.functional.FiniteStateMachine;
import ca.mcgill.model.functional.State;
import ca.mcgill.model.functional.Transition;
import ca.mcgill.model.functional.triggering.ExternalEvent;
import ca.mcgill.model.functional.triggering.InternalEvent;
import ca.mcgill.model.implementation.ImplementationModel;
import ca.mcgill.model.implementation.Task;
import ca.mcgill.model.implementation.Transaction;

public class ImplementationModelFactory {

	public ImplementationModel createImplementationModel() {
		return example2();
	}

	// This example refers to the presentation - slide 28.
	private ImplementationModel example1() {

		ImplementationModel example = null;

		// In this case I will hardcode the functional model and its
		// implementation.

		// Creating FSM1 - we need to start with transition and states.

		// States of FSM1
		State s1_0 = new State("s1,0");
		State s1_1 = new State("s1,1");
		State s1_2 = new State("s1,2");

		// Events
		ExternalEvent e1 = new ExternalEvent("e1", 40);

		InternalEvent int_e1 = new InternalEvent("int_e1");

		InternalEvent int_e2 = new InternalEvent("int_e2");

		ExternalEvent e2 = new ExternalEvent("e2", 30);

		InternalEvent int_e3 = new InternalEvent("int_e3");

		// Transitions of FSM1
		Action a1 = new Action("a1", 1, 2);
		Transition gamma1 = new Transition("gamma1", a1, s1_0, s1_1, e1, int_e1);

		Action a2 = new Action("a2", 2, 3);
		Transition gamma2 = new Transition("gamma2", a2, s1_1, s1_2, e1, int_e1);

		Action a3 = new Action("a3", 1, 2);
		Transition gamma3 = new Transition("gamma3", a3, s1_2, s1_0, e1, int_e1);

		List<Transition> trigTrans = new ArrayList<Transition>();
		trigTrans.add(gamma1);
		trigTrans.add(gamma2);
		trigTrans.add(gamma3);

		List<State> states = new ArrayList<State>();
		states.add(s1_0);
		states.add(s1_1);
		states.add(s1_2);

		FiniteStateMachine fsm1 = new FiniteStateMachine("FSM1", trigTrans,
				states);
		e1.setTriggeredTransitions(trigTrans);

		// States of FSM2
		State s2_0 = new State("s2_0");
		State s2_1 = new State("s2_1");
		State s2_2 = new State("s2_2");
		State s2_3 = new State("s2_3");

		// Transitions of FSM2
		Action a2_0 = new Action("a2_0", 1, 2);
		Transition gamma2_0 = new Transition("gamma2_0", a2_0, s2_0, s2_1,
				int_e1, int_e2);

		Action a2_1 = new Action("a2_1", 3, 4);
		Transition gamma2_1 = new Transition("gamma2_1", a2_1, s2_1, s2_2,
				int_e1, int_e2);

		Action a2_2 = new Action("a2_2", 1, 2);
		Transition gamma2_2 = new Transition("gamma2_2", a2_2, s2_2, s2_3,
				int_e1, int_e2);

		Action a2_3 = new Action("a2_3", 2, 3);
		Transition gamma2_3 = new Transition("gamma2_3", a2_3, s2_3, s2_0,
				int_e1, int_e2);

		trigTrans = new ArrayList<Transition>();
		trigTrans.add(gamma2_0);
		trigTrans.add(gamma2_1);
		trigTrans.add(gamma2_2);
		trigTrans.add(gamma2_3);

		states = new ArrayList<State>();
		states.add(s2_0);
		states.add(s2_1);
		states.add(s2_2);
		states.add(s2_3);

		FiniteStateMachine fsm2 = new FiniteStateMachine("FSM2", trigTrans,
				states);
		int_e1.setTriggeredTransitions(trigTrans);

		// States of FSM3
		State s3_0 = new State("s3_0");
		State s3_1 = new State("s3_1");

		// Transitions of FSM3
		Action a3_0 = new Action("a3_0", 3, 4);
		Transition gamma3_0 = new Transition("gamma3_0", a3_0, s3_0, s3_1,
				int_e2, null);

		Action a3_1 = new Action("a3_1", 1, 2);
		Transition gamma3_1 = new Transition("gamma3_1", a3_1, s3_1, s3_0,
				int_e2, null);

		trigTrans = new ArrayList<Transition>();
		trigTrans.add(gamma3_0);
		trigTrans.add(gamma3_1);

		states = new ArrayList<State>();
		states.add(s3_0);
		states.add(s3_1);

		FiniteStateMachine fsm3 = new FiniteStateMachine("FSM3", trigTrans,
				states);
		int_e2.setTriggeredTransitions(trigTrans);

		// States of FSM4
		State s4_0 = new State("s4_0");
		State s4_1 = new State("s4_1");

		// Transitions of FSM4
		Action a4_0 = new Action("a4_0", 2, 3);
		Transition gamma4_0 = new Transition("gamma4_0", a4_0, s4_0, s4_1, e2,
				int_e3);

		Action a4_1 = new Action("a4_1", 4, 5);
		Transition gamma4_1 = new Transition("gamma4_1", a4_1, s4_1, s4_0, e2,
				int_e3);

		trigTrans = new ArrayList<Transition>();
		trigTrans.add(gamma4_0);
		trigTrans.add(gamma4_1);

		states = new ArrayList<State>();
		states.add(s4_0);
		states.add(s4_1);

		FiniteStateMachine fsm4 = new FiniteStateMachine("FSM4", trigTrans,
				states);
		e2.setTriggeredTransitions(trigTrans);

		// States of FSM5
		State s5_0 = new State("s5_0");
		State s5_1 = new State("s5_1");
		State s5_2 = new State("s5_2");

		// Transitions of FSM5
		Action a5_0 = new Action("a5_0", 1, 2);
		Transition gamma5_0 = new Transition("gamma5_0", a5_0, s5_0, s5_1,
				int_e3, null);

		Action a5_1 = new Action("a5_1", 3, 4);
		Transition gamma5_1 = new Transition("gamma5_1", a5_1, s5_1, s5_2,
				int_e3, null);

		Action a5_2 = new Action("a5_2", 1, 2);
		Transition gamma5_2 = new Transition("gamma5_2", a5_2, s5_2, s5_0,
				int_e3, null);

		trigTrans = new ArrayList<Transition>();
		trigTrans.add(gamma5_0);
		trigTrans.add(gamma5_1);
		trigTrans.add(gamma5_2);

		states = new ArrayList<State>();
		states.add(s5_0);
		states.add(s5_1);
		states.add(s5_2);

		FiniteStateMachine fsm5 = new FiniteStateMachine("FSM5", trigTrans,
				states);
		int_e3.setTriggeredTransitions(trigTrans);

		List<FiniteStateMachine> fsms = new ArrayList<FiniteStateMachine>();
		fsms.add(fsm1);
		fsms.add(fsm2);
		fsms.add(fsm3);
		fsms.add(fsm4);
		fsms.add(fsm5);

		AsynchronousFSMsNetwork afsms = new AsynchronousFSMsNetwork(fsms);

		Task task1 = new Task("t1", fsm1, 1);
		Task task2 = new Task("t2", fsm2, 4);
		Task task3 = new Task("t3", fsm3, 5);
		Task task4 = new Task("t4", fsm4, 2);
		Task task5 = new Task("t5", fsm5, 3);
		List<Task> tasks = new ArrayList<Task>();
		tasks.add(task1);
		tasks.add(task2);
		tasks.add(task3);
		tasks.add(task4);
		tasks.add(task5);

		List<Task> trans1 = new ArrayList<Task>();
		trans1.add(task1);
		trans1.add(task2);
		trans1.add(task3);
		Transaction transaction1 = new Transaction(trans1, 40);

		List<Task> trans2 = new ArrayList<Task>();
		trans2.add(task4);
		trans2.add(task5);
		Transaction transaction2 = new Transaction(trans2, 30);

		List<Transaction> transactions = new ArrayList<Transaction>();
		transactions.add(transaction1);
		transactions.add(transaction2);

		example = new ImplementationModel(afsms, tasks, transactions);

		return example;

	}

	private ImplementationModel benefitExample1() {

		// Events
		ExternalEvent e1 = new ExternalEvent("e1", 10);

		InternalEvent int_e1 = new InternalEvent("int_e1");

		InternalEvent int_e2 = new InternalEvent("int_e2");

		ExternalEvent e2 = new ExternalEvent("e2", 20);

		// States of FSM1
		State s1_0 = new State("s1,0");
		State s1_1 = new State("s1,1");

		// Transitions of FSM1
		Action a1 = new Action("a1", 5, 5);
		Transition gamma1 = new Transition("gamma1", a1, s1_0, s1_1, e1, int_e1);

		Action a2 = new Action("a2", 4, 4);
		Transition gamma2 = new Transition("gamma2", a2, s1_1, s1_0, e1, int_e1);

		List<Transition> trigTrans = new ArrayList<Transition>();
		trigTrans.add(gamma1);
		trigTrans.add(gamma2);

		List<State> states = new ArrayList<State>();
		states.add(s1_0);
		states.add(s1_1);

		FiniteStateMachine fsm1 = new FiniteStateMachine("FSM1", trigTrans,
				states);
		e1.setTriggeredTransitions(trigTrans);

		// States of FSM2
		State s2_0 = new State("s2,0");
		State s2_1 = new State("s2,1");

		// Transitions of FSM2
		Action a2_0 = new Action("a2_0", 5, 5);
		Transition gamma2_1 = new Transition("gamma2_1", a2_0, s2_0, s2_1,
				int_e1, null);

		Action a2_1 = new Action("a2_1", 4, 4);
		Transition gamma2_2 = new Transition("gamma2_2", a2_1, s2_1, s2_0,
				int_e1, null);

		trigTrans = new ArrayList<Transition>();
		trigTrans.add(gamma2_1);
		trigTrans.add(gamma2_2);

		states = new ArrayList<State>();
		states.add(s2_0);
		states.add(s2_1);

		FiniteStateMachine fsm2 = new FiniteStateMachine("fsm2", trigTrans,
				states);

		// States of FSM3
		State s3_0 = new State("s3,0");
		State s3_1 = new State("s3,1");

		// Transitions of FSM3
		Action a3_0 = new Action("a3_0", 1, 1);
		Action a3_1 = new Action("a3_1", 1, 1);

		Transition gamma3_1 = new Transition("gamma3_1", a3_0, s3_0, s3_1, e2,
				int_e2);
		Transition gamma3_2 = new Transition("gamma3_2", a3_1, s3_1, s3_0, e2,
				int_e2);

		trigTrans = new ArrayList<Transition>();
		trigTrans.add(gamma3_1);
		trigTrans.add(gamma3_2);

		states = new ArrayList<State>();
		states.add(s3_0);
		states.add(s3_1);

		FiniteStateMachine fsm3 = new FiniteStateMachine("fsm3", trigTrans,
				states);

		// States of FSM4
		State s4_0 = new State("s4,0");
		State s4_1 = new State("s4,1");

		// Transitions of FSM4
		Action a4_0 = new Action("a4_0", 1, 1);
		Action a4_1 = new Action("a4_1", 1, 1);

		Transition gamma4_1 = new Transition("gamma4_1", a4_0, s4_0, s4_1,
				int_e2, null);
		Transition gamma4_2 = new Transition("gamma4_2", a4_1, s4_1, s4_0,
				int_e2, null);

		trigTrans = new ArrayList<Transition>();
		trigTrans.add(gamma4_1);
		trigTrans.add(gamma4_2);

		states = new ArrayList<State>();
		states.add(s4_0);
		states.add(s4_1);

		FiniteStateMachine fsm4 = new FiniteStateMachine("fsm4", trigTrans,
				states);

		List<FiniteStateMachine> fsms = new ArrayList<FiniteStateMachine>();
		fsms.add(fsm1);
		fsms.add(fsm2);
		fsms.add(fsm3);
		fsms.add(fsm4);

		Task task1 = new Task("t1", fsm1, 3);
		Task task2 = new Task("t2", fsm2, 4);
		Task task3 = new Task("t3", fsm3, 1);
		Task task4 = new Task("t4", fsm4, 2);

		List<Task> tasks = new ArrayList<Task>();
		tasks.add(task1);
		tasks.add(task2);
		tasks.add(task3);
		tasks.add(task4);

		AsynchronousFSMsNetwork fsmNet = new AsynchronousFSMsNetwork(fsms);

		List<Task> trans1 = new ArrayList<Task>();
		trans1.add(task1);
		trans1.add(task2);
		Transaction transaction1 = new Transaction(trans1, 10);

		List<Task> trans2 = new ArrayList<Task>();
		trans2.add(task3);
		trans2.add(task4);
		Transaction transaction2 = new Transaction(trans2, 20);

		List<Transaction> transactions = new ArrayList<Transaction>();
		transactions.add(transaction1);
		transactions.add(transaction2);

		ImplementationModel example = new ImplementationModel(fsmNet, tasks,
				transactions);
		return example;

	}

	private ImplementationModel example2() {

		// Events
		ExternalEvent e1 = new ExternalEvent("e1", 10);

		InternalEvent int_e1 = new InternalEvent("int_e1");

		// States of FSM1
		State s1_0 = new State("s1,0");

		// Transitions of FSM1
		Action a1 = new Action("a1", 3, 5);
		Transition gamma1 = new Transition("gamma1", a1, s1_0, s1_0, e1, int_e1);

		List<Transition> trigTrans = new ArrayList<Transition>();
		trigTrans.add(gamma1);

		List<State> states = new ArrayList<State>();
		states.add(s1_0);

		FiniteStateMachine fsm1 = new FiniteStateMachine("FSM1", trigTrans,
				states);
		e1.setTriggeredTransitions(trigTrans);

		// States of FSM2
		State s2_0 = new State("s2,0");

		// Transitions of FSM2
		Action a2_0 = new Action("a2_0", 3, 5);
		Transition gamma2_1 = new Transition("gamma2_1", a2_0, s2_0, s2_0,
				int_e1, null);

		trigTrans = new ArrayList<Transition>();
		trigTrans.add(gamma2_1);

		states = new ArrayList<State>();
		states.add(s2_0);

		FiniteStateMachine fsm2 = new FiniteStateMachine("fsm2", trigTrans,
				states);

		List<FiniteStateMachine> fsms = new ArrayList<FiniteStateMachine>();
		fsms.add(fsm1);
		fsms.add(fsm2);

		Task task1 = new Task("t1", fsm1, 3);
		Task task2 = new Task("t2", fsm2, 4);

		List<Task> tasks = new ArrayList<Task>();
		tasks.add(task1);
		tasks.add(task2);

		AsynchronousFSMsNetwork fsmNet = new AsynchronousFSMsNetwork(fsms);

		List<Task> trans1 = new ArrayList<Task>();
		trans1.add(task1);
		trans1.add(task2);
		Transaction transaction1 = new Transaction(trans1, 10);

		List<Transaction> transactions = new ArrayList<Transaction>();
		transactions.add(transaction1);

		ImplementationModel example = new ImplementationModel(fsmNet, tasks,
				transactions);
		return example;

	}

}
